Imports System.IO

Namespace DataConbversionLogic

    Public MustInherit Class BaseDataConverter

        Private Shared ReadOnly LOG_FILE As String = ".\dataconversion" & Format(Now, "yyyy_MM_dd_hhmmss") & ".log"

        Private Shared ReadOnly CLARION_BASE_DATE As Date = New System.DateTime(1800, 12, 28)

        Private Const CONN_STRING_NEW_DB As String = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=IICDB;Data Source=.\SQLEXPRESS"
        ' Private Const CONN_STRING_DATA_CON As String = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=iic_data_convert;Data Source=.\SQLEXPRESS"

        ' Public Shared dataConvConnection As DBUtils = DBUtils.getFromConnString(CONN_STRING_DATA_CON, DBUtils.enumConnType.CONN_MSSQL, DBUtils.enumSqlDialect.MSSQL)
        Public Shared newDBConnection As DBUtils = DBUtils.getFromConnString(CONN_STRING_NEW_DB, DBUtils.enumConnType.CONN_MSSQL, DBUtils.enumSqlDialect.MSSQL)

        Protected dataConvMapper As DBMapper 'mapper object connected to data conversion database
        Protected newdbMapper As DBMapper 'mapper object connected to new database 

        Private logMessages As List(Of String) = New List(Of String)

        Private totalSourceRecords As Integer
        Private sourceRecordsFailedValidation As Integer

        Private dbrecords As Integer
        Private dbFailed As Integer
        Private dbSuccess As Integer

        Public Const DATA_CONVERSION_USERNAME As String = "DC"
        Public Const INT_PAS_PASSING_GRADE As Integer = 110

        Public Property SourceWhereClause As String = String.Empty

        ''' <summary>
        ''' Retrieves all records from source database table and sends them to destination
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub dataTransfer()

            Console.Write("Starting " & Me.getTableName & "...")

            Me.instantiateMappers()

            If Me.dataConvMapper Is Nothing Then Throw New ApplicationException("dcMapper not instantiated")
            If Me.newdbMapper Is Nothing Then Throw New ApplicationException("newdbMapper not instantiated")

            Me.dataConvMapper.dbConn = newDBConnection
            Me.newdbMapper.dbConn = newDBConnection

            'set this to the new db connection.  validations inside the model objects 
            'use this connection 
            ModelContext.newCurrent(DATA_CONVERSION_USERNAME, Globalization.CultureInfo.CurrentCulture)
            ModelContext.CurrentDBUtils = newDBConnection

            'return all records from intermediary database
            Dim lstSourceObjects As IEnumerable(Of IModelObject) = dataConvMapper.findList(Me.SourceWhereClause)
            Dim lstDestinationObjects As New List(Of ModelObject)

            totalSourceRecords = lstSourceObjects.Count
            sourceRecordsFailedValidation = 0

            For Each source As IModelObject In lstSourceObjects
                'create a destination model object
                Dim destination As IModelObject = newdbMapper.getModelInstance

                If Me.checkData(source, destination) = True Then

                    Me.mapData(source, destination)

                    'inside map data we could set destination to nothing 
                    'to indicate bad data
                    If destination IsNot Nothing Then
                        lstDestinationObjects.Add(CType(destination, ModelObject))
                    Else
                        'logMsg(source.Id & " skipped, destination was set to nothing")
                        sourceRecordsFailedValidation = sourceRecordsFailedValidation + 1
                    End If
                Else

                    'Me.logMsg(source.Id & " skipped, not passed checkdata")
                    sourceRecordsFailedValidation = sourceRecordsFailedValidation + 1

                End If
            Next

            Me.saveNewObjects(lstDestinationObjects)

            Dim msgtemplate = <string>
Processed: {0} records from Source Database, {1} fail validation
Saved: {2} total records for Import, {3} success, {4} fail
</string>

            Me.logMsg(String.Format( _
                      msgtemplate.Value, _
                      totalSourceRecords, sourceRecordsFailedValidation, dbrecords, dbSuccess, dbFailed))

            File.AppendAllLines(LOG_FILE, Me.logMessages)
            Console.WriteLine("Done")

        End Sub

        ''' <summary>
        ''' Saves the new objects to the destination database
        ''' </summary>
        ''' <param name="lstDestinationObjects"></param>
        ''' <remarks></remarks>
        Private Sub saveNewObjects(ByVal lstDestinationObjects As List(Of ModelObject))
            'now save all mapped objects


            Try
                newdbMapper.beginTrans()
                For Each newobj In lstDestinationObjects
                    Try
                        dbrecords += 1
                        newdbMapper.save(newobj)
                        dbSuccess += 1
                    Catch e As Exception
                        dbFailed += 1
                        logMsg("Error Saving object:" & e.Message & vbCrLf & e.StackTrace)
                    End Try
                Next

                newdbMapper.commitTrans()

            Finally
                newdbMapper.rollbackTrans()
            End Try


        End Sub

        ''' <summary>
        ''' This sub must be overritten and map data from source to destination
        ''' </summary>
        ''' <param name="source">ModelObject containing data from Source Database</param>
        ''' <param name="destination">ModelObject to receive data from Source Database</param>
        ''' <remarks></remarks>
        Protected MustOverride Sub mapData(ByVal source As IModelObject, _
                                       ByRef destination As IModelObject)

        ''' <summary>
        ''' Instantiates dbmappers
        ''' </summary>
        ''' <remarks></remarks>
        Protected MustOverride Sub instantiateMappers()

        Protected MustOverride Function getTableName() As String

        ''' <summary>
        ''' Called before creating the object for the new database, to check for 
        ''' duplicates, skip the record under certain conditions, etc
        ''' </summary>
        ''' <param name="source"></param>
        ''' <param name="destination"></param>
        ''' <returns>True means do the record, false means skip</returns>
        ''' <remarks></remarks>
        Protected Overridable Function checkData(ByVal source As IModelObject, _
                                   ByVal destination As IModelObject) As Boolean
            Return True
        End Function

        Public Shared Function getVBDateFromClarionDate(ByVal clarionDate As Long) As DateTime

            If clarionDate = 0 Then
                Return Nothing
            Else

                Return DateAdd("d", clarionDate, CLARION_BASE_DATE)
            End If

        End Function

        Public Shared Function GetVBTimeFromClarionTime(ByVal clarionTime As Integer, _
                                                        ByVal baseDate As DateTime) As DateTime

            Dim lHours As Integer = Convert.ToInt32(clarionTime \ 360000)
            Dim lMinutes As Integer = Convert.ToInt32((clarionTime - (lHours * 360000)) \ 6000)
            Dim lSeconds As Integer = Convert.ToInt32((clarionTime - (lHours * 360000) - (lMinutes * 6000)) \ 100)
            Dim lMiliseconds As Integer = (clarionTime - (lHours * 360000) - (lMinutes * 6000) - (lSeconds * 100)) * 10

            Dim ret As New DateTime(baseDate.Year, baseDate.Month, baseDate.Day, _
                                    lHours, lMinutes, lSeconds)

            Return ret

        End Function

        Protected Sub logMsg(ByVal msg As String)
            Me.logMessages.Add(Me.getTableName & ":" & msg)
        End Sub

        Protected Sub logMsgFormat(ByVal msg As String, ByVal ParamArray args() As String)
            Me.logMessages.Add(String.Format(Me.getTableName & ":" & msg, args))
        End Sub


    End Class
End Namespace